/************************************
 * Package: RGcpp					*
 * Authors: Rui Eduardo Gouveia Gil	*
 * Date: 2010						*
 ************************************/
#include "rgcpp/sys/ThreadPool.h"

namespace rgcpp
{

ThreadPool::ThreadPool(unsigned int threadNum, unsigned int threadMem) : num(threadNum), exeNum(0)
{
	buffers = new char*[num];
	mThreads = new boost::thread*[num];

	running = true;

	for(unsigned int i=0; i<num; i++)
	{
		if(threadMem) buffers[i] = new char[threadMem];
		else buffers[i] = NULL;
		mThreads[i] = new boost::thread(boost::ref(*this));
	}

	boost::mutex::scoped_lock lock(mut);
	if(exeNum!=num)
		cond.wait(lock);

	LOG_INFO_STR("ThreadPool created");
}

ThreadPool::~ThreadPool()
{
	running = false;
	priorityQueue.release();

	for(unsigned int i=0; i<num; i++)
	{
		mThreads[i]->join();
		delete mThreads[i];
		if(buffers[i]) delete buffers[i];
	}

	delete mThreads;
	delete buffers;

	LOG_INFO_STR("ThreadPool deleted");
}

void ThreadPool::schedule(ThreadPoolInterface* object)
{
	LOG_DEBUG_DATA("TThreadPool - New job scheduled. Priority=" << object->getPriority());
	priorityQueue.addObject(object);
}

void ThreadPool::operator()()
{
	{boost::mutex::scoped_lock lock(mut);++exeNum;}
	bool result;
	int threadNum = exeNum;
	ThreadPoolInterface* object;
	LOG_DEBUG_DATA("ThreadPool - Thread "<< threadNum << "/" << num << " started");

	if(exeNum==num)
		cond.notify_one();

	while(true)
	{
		try
		{
			object = NULL;
			if(!running) return;
			object = priorityQueue.getObject();
			if(!running) return;
			LOG_TRACE_DATA("ThreadPool - Thread(" << threadNum << "): starting executing job");
			result = object->execute(buffers[threadNum-1]);
			LOG_TRACE_DATA("ThreadPool - Thread(" << threadNum << "): job successfully executed=" << (result?"true":"false"));
			result = object->final();
			LOG_TRACE_DATA("ThreadPool - Thread(" << threadNum << "): job final=" << (result?"true":"false"));
		}
		catch(Exception& e)
		{
			LOG_ERROR_DATA("ThreadPool -  Thread(" << threadNum << "):" << "\n" << e.getStackTrace());
			try{object->final();}catch(...){}
		}
		catch(std::exception& e)
		{
			LOG_ERROR_DATA("ThreadPool -  Thread(" << threadNum << "):" << e.what());
			try{object->final();}catch(...){}
		}
		catch(...)
		{
			LOG_ERROR_DATA("ThreadPool -  Thread(" << threadNum << "): exception");
			try{object->final();}catch(...){}
		}
	}
}

}
